/*
 * Copyright (c) 2010 Philip Foulkes <philip.foulkes@gmail.com>
 *
 * This file is free software and is made available under the 
 * terms of the GNU General Public License, version 2, or at your
 * option, any later version
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef _MRP_MRPDU_H_
#define _MRP_MRPDU_H_

/** 
*   The size of the various elements of an MRPDU. All sizes are in octets
*/
#define MRP_MRPDU_PROTOCOL_VERSION_SIZE		1
#define MRP_MRPDU_ATTRIBUTE_TYPE_SIZE		1
#define MRP_MRPDU_ATTRIBUTE_LENGTH_SIZE		1
#define MRP_MRPDU_ATTRIBUTE_LIST_LENGTH_SIZE		2
#define MRP_MRPDU_VECTOR_HEADER_SIZE		2
#define MRP_MRPDU_LEAVE_ALL_EVENT_SIZE		1
#define MRP_MRPDU_NUMBER_OF_VALUES_SIZE		2
#define MRP_MRPDU_THREE_PACKED_EVENTS_SIZE	1
#define MRP_MRPDU_FOUR_PACKED_EVENTS_SIZE	1
#define MRP_MRPDU_ATTRIBUTE_EVENT_SIZE		1
#define MRP_MRPDU_END_MARK_SIZE				2

/**
*   When consecutive octets are used to represent a binary number, the lower octet number has the most
*   significant value.
*/

/**
*   An AttributeEvent shall be encoded as an unsigned decimal number in the range 0 through 5. The permitted values and meanings of the AttributeEvent are as follows:
*   0:New operator
*   1:JoinIn operator
*   2:In operator
*   3:JoinMt operator
*   4:Mt operator
*   5:Lv operator
*   Further values of AttributeEvent are reserved.
*   The AttributeEvent is interpreted on receipt as a MAD event to be applied to the state machine for the Attribute defined by the AttributeType and AttributeValue to which the AttributeEvent relates.
*/
#define MRP_ATTRIBUTE_EVENT_MIN		0
#define MRP_ATTRIBUTE_EVENT_New		0
#define MRP_ATTRIBUTE_EVENT_JoinIn	1
#define MRP_ATTRIBUTE_EVENT_In		2
#define MRP_ATTRIBUTE_EVENT_JoinMt	3
#define MRP_ATTRIBUTE_EVENT_Mt		4
#define MRP_ATTRIBUTE_EVENT_Lv		5
#define MRP_ATTRIBUTE_EVENT_MAX		5

#define MRP_FOUR_PACKED_TYPE_MIN	0
#define MRP_FOUR_PACKED_TYPE_MAX	3

/**
*   A LeaveAllEvent shall be encoded as an unsigned binary number. The permitted values and meanings of LeaveAllEvent are as follows:
*   0:NullLeaveAllEvent operator
*   1:LeaveAll operator
*   Further values of LeaveAllEvent are reserved.
*   The LeaveAllEvent is interpreted on receipt as a MAD Leave All event to be applied to the state machines for all Attributes of the type defined by the AttributeType field.
*/
#define MRP_LEAVE_ALL_EVENT_MIN					0 /* the value of this macro should be set to the value of the first leave all event */
#define MRP_LEAVE_ALL_EVENT_NullLeaveAllEvent	0
#define MRP_LEAVE_ALL_EVENT_LeaveAll			1
#define MRP_LEAVE_ALL_EVENT_MAX					1 /* the value of this macro should be set the the value of the last leave all event */

/**
*   An EndMark shall be encoded as two octets, taken to represent the unsigned binary number. It takes the numeric value 0.
*   Further values of EndMark are reserved and shall not be used.
*/
#define MRP_MRPDU_EndMark		0

/**
*   MRPDU ::= ProtocolVersion, Message {, Message}, EndMark
*   ProtocolVersion BYTE ::= Defined by the specific MRP application
*   Message ::= AttributeType, AttributeLength, AttributeList
*   AttributeType BYTE ::= Non-zero integer defined by the specific MRP application
*   AttributeLength BYTE ::= Non-zero integer defined by the specific MRP application
*   AttributeList ::= VectorAttribute {, VectorAttribute}, EndMark
*   VectorAttribute ::= VectorHeader, FirstValue, Vector
*   VectorHeader SHORT ::= (LeaveAllEvent * 8192) + NumberOfValues
*   FirstValue ::= Defined by the specific MRP application
*   Vector ::= ThreePackedEvents {, ThreePackedEvents}
*   ThreePackedEvents BYTE ::= (((((AttributeEvent) *6) + AttributeEvent) *6) + AttributeEvent)
*   AttributeEvent BYTE ::= New | JoinIn | In | JoinMt | Mt | Lv
*   LeaveAllEvent BYTE ::= NullLeaveAllEvent | LeaveAll
*   NumberOfValues SHORT ::= Number of events encoded in the vector
*   EndMark BYTE SHORT ::= 0x0000 | End of PDU
*   NullLeaveAllEvent ::= 0
*   LeaveAll ::= 1
*   New ::= 0
*   JoinIn ::= 1
*   In ::= 2
*   JoinMt ::= 3
*   Mt ::= 4
*   Lv ::= 5
*/

#define MRP_OUT
#define MRP_IN
#define MRP_INOUT

struct mrp_mrpdu
{
	struct sk_buff * skb;
	
	u8 * data;
	u8 * curr;
	
	int use_attribute_list_length;
	u8 * last_attribute_list_length;
	
	int owns_skb;
	
	u8 last_attribute_length;
	u16 last_number_of_values;
	
	struct mrp * mrp;
};

struct mrp_mrpdu * mrp_mrpdu_create_and_init (struct mrp * mrp, int mrpdu_length, int use_attribute_list_length);
struct mrp_mrpdu * mrp_mrpdu_create_and_init_with_supplied_sk_buff (struct mrp * mrp, struct sk_buff * skb, int own_sk_buff, int use_attribute_list_length);
void mrp_mrpdu_destroy (struct mrp_mrpdu ** mrp_mrpdu);

int mrp_mrpdu_does_use_attribute_list_length (struct mrp_mrpdu * mrp_mrpdu);

void reset_curr (struct mrp_mrpdu * mrp_mrpdu);

u8 * mrp_mrpdu_get_data (struct mrp_mrpdu * mrp_mrpdu);
int mrp_mrpdu_get_data_length (struct mrp_mrpdu * mrp_mrpdu);

int mrp_mrpdu_peek (struct mrp_mrpdu * mrp_mrpdu, void * data, int length);

int mrp_mrpdu_pack_test_mrpdu (struct mrp_mrpdu * mrp_mrpdu);
int mrp_mrpdu_print (struct mrp_mrpdu * mrp_mrpdu);

struct sk_buff * mrp_mrpdu_get_sk_buff (struct mrp_mrpdu * mrp_mrpdu, int disown_skb);
struct sk_buff * mrp_mrpdu_get_sk_buff_clone (struct mrp_mrpdu * mrp_mrpdu);
int mrp_mrpdu_set_sk_buff_ownership (struct mrp_mrpdu * mrp_mrpdu, int owns_skb);

struct ethhdr * mrp_mrpdu_get_ethernet_header(struct mrp_mrpdu * mrp_mrpdu);

/**
*   These methods are used for buidling up an MRPDU. Use them in the order that the 
*   various MRPDU elements have to appear in the PDU. 
*   ie, First call mrp_mrpdu_set_protocol_version, then call mrp_mrpdu_add_attribute_type, etc. 
*/
int mrp_mrpdu_set_protocol_version 		(struct mrp_mrpdu * mrp_mrpdu, u8 protocol_version);
int mrp_mrpdu_add_attribute_type 		(struct mrp_mrpdu * mrp_mrpdu, u8 attribute_type);
int mrp_mrpdu_add_attribute_length 		(struct mrp_mrpdu * mrp_mrpdu, u8 attribute_length);
int mrp_mrpdu_add_vector_header 		(struct mrp_mrpdu * mrp_mrpdu, u8 leave_all_event, u16 number_of_values);
int mrp_mrpdu_add_first_value 			(struct mrp_mrpdu * mrp_mrpdu, void * first_value, int first_value_length);
int mrp_mrpdu_add_three_packed_events 	(struct mrp_mrpdu * mrp_mrpdu, u8 attribute_event_1, u8 attribute_event_2, u8 attribute_event_3);
int mrp_mrpdu_add_four_packed_events	(struct mrp_mrpdu * mrp_mrpdu, u8 four_packed_type_1, u8 four_packed_type_2, u8 four_packed_type_3, u8 four_packed_type_4);
int mrp_mrpdu_add_attribute_list_end_mark (struct mrp_mrpdu * mrp_mrpdu, u16 end_mark);
int mrp_mrpdu_add_mrpdu_end_mark 		(struct mrp_mrpdu * mrp_mrpdu, u16 end_mark);
/* ======================================================================================================================== */


/**
*   These methods are used for picking out the elements of an MRPDU. Use them in the order that the 
*   various MRPDU elements appear in the PDU. 
*   ie, First call mrp_mrpdu_get_protocol_version, then call mrp_mrpdu_get_attribute_type, etc. 
*/
int mrp_mrpdu_get_protocol_version (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u8 * protocol_version);
int mrp_mrpdu_get_attribute_type (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u8 * attribute_type);
int mrp_mrpdu_get_attribute_length (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u8 * attribute_length);
int mrp_mrpdu_get_attribute_list_length (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u16 * attribute_list_length);
int mrp_mrpdu_get_vector_header (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u8 * leave_all_event, MRP_OUT u16 * number_of_values);
int mrp_mrpdu_get_first_value (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT void * first_value, int first_value_length);
int mrp_mrpdu_get_three_packed_events (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u8 * attribute_event_1, MRP_OUT u8 * attribute_event_2, MRP_OUT u8 * attribute_event_3);
int mrp_mrpdu_get_four_packed_events (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u8 * four_packed_type_1, MRP_OUT u8 * four_packed_type_2, MRP_OUT u8 * four_packed_type_3, MRP_OUT u8 * four_packed_type_4);
int mrp_mrpdu_get_end_mark (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u16 * end_mark);
/* ======================================================================================================================== */

int mrp_mrpdu_get_bytes (struct mrp_mrpdu * mrp_mrpdu, MRP_OUT u8 * bytes, int num_bytes);

int mrp_mrpdu_get_three_packed_events_from_byte (u8 three_packed_events, MRP_OUT u8 * attribute_event_1, MRP_OUT u8 * attribute_event_2, MRP_OUT u8 * attribute_event_3);
int mrp_mrpdu_get_four_packed_events_from_byte  (u8 four_packed_events,  MRP_OUT u8 * four_packed_type_1, MRP_OUT u8 * four_packed_type_2, MRP_OUT u8 * four_packed_type_3, MRP_OUT u8 * four_packed_type_4);

#endif
